﻿using System;
using System.Globalization;
using System.Linq;
using System.Text;

using Wiki.Data;

namespace Wiki.Web.Models
{
    public sealed class WikiPage
    {
        public WikiPage(string title)
            : this(title, String.Empty, null, null, null)
        { }

        public WikiPage(string title, string body, Guid? guid, DateTime? lastModified, DateTime? removed)
        {
            this.Title = title;
            this.Body = body;
            this.Guid = guid;
            this.LastModified = lastModified;
            this.Removed = removed;
        }

        public string Title { get; set; }

        public string Body { get; set; }

        public Guid? Guid { get; set; }

        public DateTime? LastModified { get; set; }

        public DateTime? Removed { get; set; }

        public bool IsAvailable
        {
            get
            {
                return (this.Guid.HasValue && !this.Removed.HasValue);
            }
        }

        public string BodyAsHtml
        {
            get
            {
                StringBuilder buffer = null;

                if (this.Body != null)
                {
                    buffer = new StringBuilder(this.Body.Length);
                    if (this.Body.Length != 0)
                    {
                        string body = this.Body;
                        int index = 0;
                        while (index != -1)
                        {
                            index = body.IndexOf("[[");
                            if (index == -1)
                            {
                                buffer.Append(body);
                            }
                            else
                            {
                                buffer.Append(body.Substring(0, index));
                                body = body.Substring(index + 2);
                                index = body.IndexOf("]]");
                                if (index == -1)
                                {
                                    buffer.Append("[[");
                                    buffer.Append(body);
                                }
                                else
                                {
                                    buffer.Append(FormatAnchor(body.Substring(0, index)));
                                    body = body.Substring(index + 2);
                                }
                            }
                        }
                    }
                }

                return (buffer == null) ? null as string : buffer.ToString();
            }
        }

        public static WikiPage Edit(string title, string body)
        {
            PageTable page = null;

            WikiDataContext wiki = new WikiDataContext();
            var query = from p in wiki.PageTables
                        where p.Title == title
                        select p;

            if ((query != null) && (query.Count<PageTable>() != 0)) page = query.First<PageTable>();

            if (page == null)
            {
                page = new PageTable();
                page.Title = title;
                page.Guid = System.Guid.NewGuid();
                wiki.PageTables.InsertOnSubmit(page);
            }

            page.Body = body;
            page.LastModified = DateTime.UtcNow;
            page.Removed = null;

            wiki.SubmitChanges();

            return new WikiPage(
                    page.Title,
                    page.Body,
                    page.Guid,
                    page.LastModified,
                    page.Removed
                    );
        }

        public static WikiPage Query(string title)
        {
            WikiPage obj = null;

            if (!title.IsNullOrEmpty())
            {
                WikiDataContext wiki = new WikiDataContext();
                var query = from p in wiki.PageTables
                            where p.Title == title && p.Removed == null
                            select p;

                PageTable page = null;
                if ((query != null) && (query.Count<PageTable>() != 0))
                {
                    page = query.First<PageTable>();
                    obj = new WikiPage(
                        page.Title,
                        page.Body,
                        page.Guid,
                        page.LastModified,
                        page.Removed
                        );
                }
            }

            return obj ?? new WikiPage(title);
        }

        public static WikiPage Remove(string title)
        {
            WikiPage obj = null;

            if (!title.IsNullOrEmpty())
            {
                WikiDataContext wiki = new WikiDataContext();
                var query = from p in wiki.PageTables
                            where p.Title == title
                            select p;

                PageTable page = null;
                if ((query != null) && (query.Count<PageTable>() != 0))
                {
                    page = query.First<PageTable>();
                    page.Removed = DateTime.UtcNow;
                    wiki.SubmitChanges();
                }
            }

            return obj ?? new WikiPage(title);
        }

        private static string FormatAnchor(string value)
        {
            return value.IsNullOrEmpty() ? value : String.Format(CultureInfo.InvariantCulture, "<a href=\"{0}\" rel=\"bookmark\">{0}</a>", value);
        }
    }
}